package com.antdant.service;

import com.alibaba.fastjson.JSON;
import com.antdant.constant.UserConstant;
import com.antdant.entity.User;
import com.antdant.exception.GeneralException;
import com.antdant.exception.NeedLoginException;
import com.antdant.model.SmsSendDto;
import com.antdant.utils.*;
import com.antdant.model.UserLoginVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;

/**
 * @Author Lee Yunc
 * @Date 2021/2/23 14:40
 * @Description: 登录服务
 * @Version 1.0
 */
@Service
public class LoginService {

    @Resource
    private RedisService redisService;

    @Resource
    private UserService userService;

    @Resource
    private UserLoginLogService userLoginLogService;

    @Resource
    private SmsService smsService;

    /**
     * 用户登录
     *
     * @param ip        登录IP
     * @param loginUser 用户信息
     * @param userAgent 用户代理
     * @return
     * @throws UnsupportedEncodingException
     */
    public UserLoginVo login(String ip, User loginUser, String userAgent) throws UnsupportedEncodingException {
        if (DataUtils.isEmptyStr(loginUser.getLoginId())) {
            throw new GeneralException("学号或密码错误，请确认!");
        }

        User user = userService.getUserByLoginId(loginUser.getLoginId());

        if (DataUtils.isNull(user)) {
            throw new GeneralException("学号或密码错误，请确认!");
        }
        //校验登录密码
        if (PasswordUtils.isNotEqual(loginUser.getPassword(), user.getPassword())) {
            throw new GeneralException("学号或密码错误，请确认!");
        } else {
            String userToken = UserTokenUtils.generateUserToken(loginUser.getLoginId());
            UserLoginVo userLoginVo = UserLoginVo.factory(user, userToken);
            cacheLoginUser(userToken, userLoginVo);
            userLoginLogService.addLoginLog(ip, userLoginVo, userAgent);
            return userLoginVo;
        }
    }

    /**
     * 缓存登录用户的信息到redis
     *
     * @param userToken   用户token
     * @param userLoginVo 用户信息
     */
    private void cacheLoginUser(String userToken, UserLoginVo userLoginVo) {
        redisService.set(UserTokenUtils.generateUserTokenCacheKey(userToken), JSON.toJSONString(userLoginVo),
                UserConstant.USER_TOKEN_EXPIRE);
    }

    /**
     * 登录用户缓存key续时间
     *
     * @param userToken
     */
    public void refreshLoginUserExpire(String userToken) {
        String cacheKey = UserTokenUtils.generateUserTokenCacheKey(userToken);
        if (redisService.hasKey(cacheKey)) {
            redisService.expire(cacheKey, UserConstant.USER_TOKEN_EXPIRE);
        }
    }

    /**
     * 退出登录
     *
     * @param request
     */
    public void logout(HttpServletRequest request) {
        String userToken = getUserTokenHeader(request);
        String cacheKey = UserTokenUtils.generateUserTokenCacheKey(userToken);
        if (redisService.hasKey(cacheKey)) {
            UserLoginVo userLoginVo = getLoginUserVo(userToken);
            redisService.delete(cacheKey);
            userLoginLogService.addLogoutLog(IpUtils.getIP(request), userLoginVo, IpUtils.getUserAgent(request));
        }
    }

    /**
     * 获取登录用户信息
     *
     * @param userToken 用户token
     * @return
     */
    public User getLoginUser(String userToken) {
        try {
            return getLoginUserVo(userToken).getUser();
        } catch (Exception e) {
            throw new NeedLoginException("需要登录，请登录！");
        }
    }

    /**
     * 获取登录用户信息
     *
     * @param userToken
     * @return
     */
    public UserLoginVo getLoginUserVo(String userToken) {
        String cacheStr = redisService.get(UserTokenUtils.generateUserTokenCacheKey(userToken));
        if (DataUtils.isEmptyStr(cacheStr)) {
            throw new NeedLoginException("需要登录，请登录！");
        }
        try {
            UserLoginVo userLoginVo = JSON.parseObject(cacheStr, UserLoginVo.class);
            return userLoginVo;
        } catch (Exception e) {
            throw new NeedLoginException("需要登录，请登录！");
        }
    }

    /**
     * 从请求头中获取USER_TOKEN
     *
     * @param request 请求对象
     * @return
     */
    public String getUserTokenHeader(HttpServletRequest request) {
        String userToken = request.getParameter(UserConstant.USER_TOKEN_HEADER_KEY);
        if (DataUtils.isEmptyStr(userToken)) {
            userToken = request.getHeader(UserConstant.USER_TOKEN_HEADER_KEY);
        }
        return userToken;
    }

    /**
     * 忘记密码的时候：发送验证码
     *
     * @param toEmail
     * @return
     */
    public String sendVerifyCode(String toEmail) {
        //生成一个随机的验证码
        String emailServiceCode = VerifyCodeUtils.generateVerifyCode();
        SmsSendDto message = new SmsSendDto();
        message.setSubject("修改密码验证码：");
        message.setTextContent("验证码是：" + emailServiceCode);
        message.setToUser(toEmail);
        smsService.sendSimpleTextMail(message);
        return emailServiceCode;
    }

    /**
     * 刷新token
     *
     * @param request
     * @return
     */
    public UserLoginVo refreshToken(HttpServletRequest request) throws UnsupportedEncodingException {
        String userToken = getUserTokenHeader(request);
        String cacheKey = UserTokenUtils.generateUserTokenCacheKey(userToken);
        if (redisService.hasKey(cacheKey)) {
            String loginId = getLoginUserVo(userToken).getUser().getLoginId();
            User user = userService.getUserByLoginId(loginId);
            String token = UserTokenUtils.generateUserToken(loginId);
            UserLoginVo userLoginVo = UserLoginVo.factory(user, token);
            cacheLoginUser(token, userLoginVo);
            redisService.delete(cacheKey);
            return userLoginVo;
        }
        return null;
    }
}
